package cn.antblog.multi.datasource.autoconfig;

import cn.antblog.multi.datasource.aspectJ.DynamicDataSourceAdviser;
import cn.antblog.multi.datasource.constant.Const;
import cn.antblog.multi.datasource.properties.DataSourceProp;
import cn.antblog.multi.datasource.properties.MultiDataSourceProperties;
import cn.antblog.multi.datasource.service.MultiDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Resource;
import javax.sound.midi.Soundbank;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author yangjy
 * @version 1.0
 * @description: 创建数据源配置类
 * @date 2022/11/22 11:31
 */
@Configuration
@EnableConfigurationProperties(MultiDataSourceProperties.class)
public class MultiDataSourceConfig {

    public static final String DS_TYPE = "dsType";

    @Resource
    private MultiDataSourceProperties multiDataSourceProperties;

    private DataSource createDs(DataSourceProp dsProp) {
        DataSource dataSource = null;
        try {
            Class<?> dsClass = Class.forName(dsProp.get(DS_TYPE));
            if(DataSource.class.isAssignableFrom(dsClass)){
                dataSource  = (DataSource) dsClass.getConstructor().newInstance();
                DataSource finalDataSource = dataSource;
                ReflectionUtils.doWithFields(dsClass,field -> {
                    System.out.printf("字段:%s;具有%n", field);
                    System.out.println(" dsProp.get(field.getName())--"+ dsProp.get(field.getName()));
                    // 指示反射的对象在使用时应该取消 Java 语言访问检查 可以访问私有
                    field.setAccessible(true);
                    field.set(finalDataSource , dsProp.get(field.getName()));
                },field -> {
                    System.out.println("********************************************************************");
                    System.out.println("dsProp.get(DS_TYPE)--"+dsProp.get(DS_TYPE));
                    System.out.println("field.getName()--"+field.getName());
                    if (Objects.equals(dsProp.get(DS_TYPE), field.getName())) {
                        System.out.println("falsefalsefalsefalsefalsefalsefalsefalsefalse");
                        return false;
                    }
                    System.out.println("dsProp.get(field.getName())--"+dsProp.get(field.getName()));
                    return Objects.nonNull(dsProp.get(field.getName()));
                });
                System.out.println("///////////////////////////////////////////////////////" + finalDataSource);
            }

        }catch (Exception e){
            throw new RuntimeException(e);
        }
        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ = " + dataSource);
        return dataSource;
    }

    @Bean(Const.MULTI_DS)
    @Primary
    public DataSource multiDataSource(){
        MultiDataSource multiDataSource = new MultiDataSource();

        Map<Object, Object> dataSourceMap = new HashMap<>(multiDataSourceProperties.getDataSourcePropMap().size());

        Map<String, DataSourceProp> dataSourcePropMap = multiDataSourceProperties.getDataSourcePropMap();

        dataSourcePropMap.forEach((lookupKey,dsProp) -> {
            dataSourceMap.put(lookupKey, createDs(dsProp));
        });
        //创建多数据源
//        定义DynamicDataSource类继承抽象类AbstractRoutingDataSource，并实现了determineCurrentLookupKey()方法。
//        把配置的多个数据源会放在AbstractRoutingDataSource的 targetDataSources和defaultTargetDataSource中，
//        然后通过afterPropertiesSet()方法将数据源分别进行复制到resolvedDataSources和resolvedDefaultDataSource中。
//        调用AbstractRoutingDataSource的getConnection()的方法的时候，先调用determineTargetDataSource()方法返回DataSource在进行getConnection()。
        //把多种数据源放进去
        multiDataSource.setTargetDataSources(dataSourceMap);
        //设置默认数据源
        multiDataSource.setDefaultTargetDataSource(dataSourceMap.get(Const.DEFAULT));
        return multiDataSource;
    }

    /**
     * 设置数据源的事务
     * @param multiDataSource
     * @return
     */
    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(
            //引入上面的数据源
            @Qualifier(Const.MULTI_DS) DataSource multiDataSource
    ) {
        DataSourceTransactionManager tx = new DataSourceTransactionManager();
        tx.setDataSource(multiDataSource);
        return tx;
    }

    /**
     * 将aop 注入到容器中
     * @return
     */
    @Bean
    public DynamicDataSourceAdviser dynamicDataSourceAdviser() {
        return new DynamicDataSourceAdviser();
    }



}
